#!/usr/bin/python2.6

import hashlib
import logging
import json
import webapp2

from google.appengine.ext import blobstore
from google.appengine.ext import deferred
from google.appengine.ext import db
from google.appengine.ext.webapp import blobstore_handlers

from lib import cache
from lib import models
from lib import parse_replay
from lib import populate
from lib import simulate_build


class SimulateBuild(cache.RequestHandler):

  def get_internal(self):
    build_order = self.request.get_all('build')
    version = self.request.get('version')
    race = self.request.get('race')
    map = self.request.get('map')

    state = simulate_build.State(version, race, map)

    for name in build_order:
      state.Enqueue(name.strip())

    try:
      state.Run()
    except simulate_build.DeadlockError:
      pass

    response = {
      'buildables': {},
      'events': [],
    }
    for event in state.event_history:
      event_dict = dict((x, getattr(event, x)) for x in event.properties())
      event_dict.update({'obj': event.obj})
      if event.obj and event.obj.buildable:
        buildable = event.obj.buildable
        response['buildables'][buildable.name] = buildable.AsDict()
        event_dict['buildable'] = event.obj.buildable.name
        event_dict['object_id'] = id(event.obj)
        del event_dict['obj']
      response['events'].append(event_dict)
    json.dump(response, self.response.out)
    cache.SaveToMemcache()


class Populate(webapp2.RequestHandler):
  def get(self):
    populate.Populate()
    self.response.out.write('Done!')


class GetReplayUploadURL(webapp2.RequestHandler):
  def get(self):
    upload_url = blobstore.create_upload_url('/api/uploadReplay')
    json.dump({'url': upload_url}, self.response.out)


class UploadReplay(blobstore_handlers.BlobstoreUploadHandler):
  def post(self):
    upload_files = self.get_uploads('file')
    result = {}
    for blob_key in upload_files:
      blob_reader = blobstore.BlobReader(blob_key)
      sha256 = hashlib.sha256(blob_reader.read()).hexdigest()
      previous_replay = (models.Replay.all()
                                      .filter('sha256 =', sha256)
                                      .get())
      if previous_replay:
        result[blob_key.filename] = {
          'result': 'error',
          'message': 'Duplicate hash %s' % sha256,
        }
        blob_key.delete()
        continue
      replay = models.Replay(
        blob = blob_key,
        sha256 = sha256)
      replay.put()
      result[blob_key.filename] = {
        'result': 'success'
      }
    json.dump(result, self.response.out)


class ParseReplays(webapp2.RequestHandler):
  def get(self):
    batch_task = models.BatchTask()
    batch_task.put()
    deferred.defer(parse_replay.FetchAndParseReplays, batch_task.key(), None, 50)
    json.dump({
      'batch_task_key': str(batch_task.key()),
    }, self.response.out)


class GetBatchTaskStatus(webapp2.RequestHandler):
  def get(self):
    batch_task_key = self.request.get('batch_task_key')
    batch_task = models.BatchTask.get(batch_task_key)
    result = {
      'task_status': models.EntityAsDict(batch_task),
      'task_results': [],
    }
    for task_result in batch_task.taskresult_set:
      result['task_results'].append({
        'result': task_result.result,
        'target': str(task_result.target.key()),
      })
    json.dump(result, self.response.out)


class GetBuildables(cache.RequestHandler):
  def get_internal(self):
    version_str = self.request.get('version')
    race_str = self.request.get('race')
    (version_query, race_query) = cache.QueryMulti([
        db.Query(models.Version)
          .filter('version =', version_str),
        db.Query(models.Race)
          .filter('name =', race_str),
    ])

    version = list(version_query)[0]
    race = list(race_query)[0]
    (buildables_query,) = cache.QueryMulti([
        db.Query(models.Buildable)
          .filter('version =', version)
          .filter('race =', race),
    ])

    response = [buildable.AsDict() for buildable in buildables_query]
    json.dump(response, self.response.out)


app = webapp2.WSGIApplication([
  ('/api/getBatchTaskStatus', GetBatchTaskStatus),
  ('/api/getBuildables', GetBuildables),
  ('/api/getReplayUploadURL', GetReplayUploadURL),
  ('/api/parseReplays', ParseReplays),
  ('/api/populate', Populate),
  ('/api/simulateBuild', SimulateBuild),
  ('/api/uploadReplay', UploadReplay),
])
